<?php
/**
 * Each engineer has a duty to keep the code elegant
 * Created by wolffy.
 * Author @wolffy<13750088090@sina.cn>
 * Date: 2018/8/19
 * Time: 19:30
 */
namespace App\Services;

use App\Repositories\BankSupportRepository;
use App\Repositories\PassageRepository;
use App\Repositories\RepaymentBillRepository;
use App\Repositories\UserCreditCardRepository;
use App\Repositories\UserLevelPassageRepository;
use App\Repositories\UserPassageRepository;
use App\Repositories\UserRepository;
use Illuminate\Support\Facades\DB;

class RepaymentBillServiceOldTwo extends CommonService
{
    protected $userRepository;
    protected $userCreditCardRepository;
    protected $repaymentBillRepository;
    protected $repaymentPlanServiceCharge;
    protected $lowestCardMoney;
    protected $endFor;
    protected $passageRepository;
    protected $userPassageRepository;
    protected $userLevelPassageRepository;
    protected $bankSupportRepository;

    public function __construct(UserRepository $userRepository, UserCreditCardRepository $userCreditCardRepository,
                                RepaymentBillRepository $repaymentBillRepository, PassageRepository $passageRepository,
                                UserPassageRepository $userPassageRepository, UserLevelPassageRepository $userLevelPassageRepository,
                                BankSupportRepository $bankSupportRepository)
    {
        $this->userRepository = $userRepository;
        $this->userCreditCardRepository = $userCreditCardRepository;
        $this->repaymentBillRepository = $repaymentBillRepository;
        $this->passageRepository = $passageRepository;
        $this->userPassageRepository = $userPassageRepository;
        $this->userLevelPassageRepository = $userLevelPassageRepository;
        $this->bankSupportRepository = $bankSupportRepository;
    }

    /**
     * 还款设置与选择账单还款日期
     * @param $id
     * @param $billDay
     * @param $repaymentDay
     * @return \Illuminate\Http\JsonResponse
     */
    public function repaymentBillSet($userId, $id)
    {
        //判断是否有绑定
        $isBind = $this->userCreditCardRepository->validateCreditCardIsUser($id, $userId);
        if (empty($isBind->bank_no) || 0 == $isBind->is_bind) {
            return $this->responseJson(10306);//信用卡不存在
        }
        $billRepaymentDate = billRepaymentDate($isBind->bill_day, $isBind->repayment_day);
        //一个月有上个和这个还款日，两个的处理
        $monthBillDate = getMonthBillDate($isBind->bill_day, $isBind->repayment_day);
        if (date('Y-m') != $monthBillDate) {
            $billRepaymentDate = [
                'bill_last_date' => date('Ymd', strtotime("-1 months", strtotime($billRepaymentDate['bill_last_date']))),//上个月账单日
                'repayment_last_date' => date('Ymd', strtotime("-1 months", strtotime($billRepaymentDate['repayment_last_date']))),//上个还款日
                'bill_date' => $billRepaymentDate['bill_last_date'],//本月账单日
                'repayment_date' => $billRepaymentDate['repayment_last_date'],//还款日
                'diff_days' => diffDate($billRepaymentDate['bill_last_date'], $billRepaymentDate['repayment_last_date']),
            ];
        }
        $repaymentDate = getDateFromRange($billRepaymentDate['bill_date'], $billRepaymentDate['repayment_date']);
        $data = [];
        $limitStartTime = strtotime('09:29:00');
        $limitEndTime = strtotime('23:59:59');
        foreach ($repaymentDate as $key=>$value) {
            if ($key < count($repaymentDate) - 1) {
                //判读是否今天
                if (date('Y-m-d') == date('Y-m-d', $value)) {
                    if (time() >= $limitStartTime && time() < $limitEndTime) {
                        $status = 0;
                    } else {
                        $status = 1;
                    }
                } else if (date('Y-m-d') < date('Y-m-d', $value)) {
                    $status = 1;
                } else {
                    $status = 0;
                }
            } else {
                $status = 0;
            }
            $month = date('m', $value);
            $data[$month]['month'] = $month . '月';
            $data[$month]['days'][] = [
                'days' => date('d', $value),
                'days_date' => date('Y-m-d', $value),
                'status' => $status,
            ];
        }
        $data = array_values($data);
        //获取账单
        $lastBillDate = strtotime($billRepaymentDate['bill_last_date']) + 86400;
        $billDate = strtotime($billRepaymentDate['bill_date']);
        $repaymentDate = strtotime($billRepaymentDate['repayment_date']);
        $bill = $this->repaymentBillRepository->getRepaymentBill($userId, $id, $monthBillDate);
        if (!empty($bill)) {
            $isRepaymentMoney = $bill->repayment_bill_money;
            $this->repaymentBillRepository->updateDate($userId, $id, $monthBillDate, $lastBillDate, $billDate, $repaymentDate);
        } else {
            $this->repaymentBillRepository->create([
                'bill_sn' => makeOrderNo(),
                'user_id' => $userId,
                'credit_card_id' => $id,
                'last_bill_date' => $lastBillDate,
                'bill_date' => $billDate,
                'repayment_date' => $repaymentDate,
                'bill_status' => billStatus($billRepaymentDate['bill_date'], $billRepaymentDate['repayment_date'], 0),
                'month_bill_date' => $monthBillDate,
                'create_time' => time(),
            ]);
            $isRepaymentMoney = '';
        }
        $result = [
            'repayment_money' => $isRepaymentMoney,
            'repayment_plan' => $data
        ];
        return $this->responseJson(0, $result);
    }

    /**
     * 推荐天数
     * @param $userLevel
     * @param $repaymentDay
     * @param $repaymentMoneys
     * @param $bankCode
     * @return \Illuminate\Http\JsonResponse
     */
    public function recommendDays($userLevel, $repaymentDay, $repaymentMoneys, $bankCode, $selectDays, $isDefault)
    {
        $result = $this->recommend($userLevel, $repaymentDay, $repaymentMoneys, $bankCode, $selectDays, $isDefault);
        if (is_object($result)) return $result;
        return $this->responseJson(0, $result);
    }

    /**
     * 推荐
     * @param $userLevel
     * @param $repaymentDay
     * @param $repaymentMoneys
     * @param $bankCode
     * @param $selectDays
     * @param $isDefault
     * @return array|\Illuminate\Http\JsonResponse
     */
    public function recommend($userLevel, $repaymentDay, $repaymentMoneys, $bankCode, $selectDays = 0, $isDefault = 0)
    {
        if (0 == $isDefault) {
            $needDays = $selectDays;
            if ($needDays < 2) {
                return $this->responseJson(10520);//至少选择2天以上
            }
        } else {
            $remainingRepaymentDays = $this->remainingRepaymentDays($repaymentDay);//剩余天数
            $needDays = $remainingRepaymentDays['remaining_days'];
            if ($needDays < 2) {
                return $this->responseJson(10521);//剩余还款天数至少3天以上
            }
        }
        $repaymentMoneyAll = roundNo($repaymentMoneys);//不四舍五入保留两位
        $getSupportPassage = $this->getSupportPassage($bankCode, $repaymentMoneyAll,
            $needDays, $userLevel);
        if (empty($getSupportPassage) || 0 == $getSupportPassage['recommend_days']) {
            return $this->responseJson(10504);//还款金额过大所选还款天数不足
        }
        if (0 == $isDefault) {
            $recommendDays = $selectDays;
        } else {
            $recommendDays = $getSupportPassage['recommend_days'];
        }
        //推荐天数、还款金额、还款手续费、最低卡余额、通道id
        $repaymentPlanServiceCharge = $this->repaymentPlanServiceCharge($getSupportPassage['repayment_money'], $getSupportPassage['personal_rate'],
            $recommendDays, $getSupportPassage['times'], $getSupportPassage['second_rate']);
        $result = [
            'repayment_money' => $getSupportPassage['repayment_money'],
            'repayment_service_charge' => $repaymentPlanServiceCharge,
            'lowest_card_money' => $this->lowestCardMoney($getSupportPassage['repayment_money'], $recommendDays,
                $getSupportPassage['times'], $repaymentPlanServiceCharge),
            'passage_id' => $getSupportPassage['passage_id'],
            'recommend_days' => $getSupportPassage['recommend_days'],
            'highest_money' => $getSupportPassage['highestOneDayOneTimesRepaymentMoney'],
            'personal_rate' => $getSupportPassage['personal_rate'],//会员使用费率
            'second_rate' => $getSupportPassage['second_rate'],//秒到费
            'times' => $getSupportPassage['times'],//还款笔数
        ];
        return $result;
    }

    /**
     * 推荐方案天数
     * @param $passageId '1小额c还款 3大额e还款'
     * @param $bankCode
     * @param $repaymentMoney
     * @param $personalRate
     * @param $secondRate
     * @return array
     */
    public function isCanRecommend($passageId, $bankCode, $repaymentMoney, $personalRate, $secondRate, $isDefault = true)
    {
        $repaymentEveryTimeMoney = 1000;
        if ($passageId == 1) {
            $bankSupport = $this->bankSupportRepository->byPassageIdAndBankCode($passageId, $bankCode);
            if (!empty($bankSupport) && $bankSupport->is_support == 0) {
                if ($isDefault) {
                    $passageId = 3;
                } else {
                    return [];
                }
            }
            $repaymentEveryTimeMoney = 1000;
        }
        if ($passageId == 3) {
            $bankSupport = $this->bankSupportRepository->byPassageIdAndBankCode($passageId, $bankCode);
            if (empty($bankSupport) || $bankSupport->is_support == 0) {
                return [];
            }
            $repaymentEveryTimeMoney = (int)roundNo($bankSupport->every_time_money / 3);
        }
        $highestMoney = $this->highestOneDayOneTimesRepaymentMoney($passageId, $repaymentMoney, $personalRate, $secondRate, $repaymentEveryTimeMoney);
        return $highestMoney;
    }

    /**
     * 根据天数选择通道
     * @param $bankCode
     * @param $repaymentMoney
     * @param $selectDays
     * @param $userLevel
     * @param $passageId
     * @return \Illuminate\Http\JsonResponse
     */
    public function selectPassage($bankCode, $repaymentMoney, $selectDays, $userLevel, $passageId)
    {
        if ($selectDays < 2) {
            return $this->responseJson(10520);//至少选择2天以上
        }
        $data = $this->checkPassage($bankCode, $repaymentMoney, $selectDays, $userLevel, $passageId);
        if (is_object($data)) return $data;
        return $this->responseJson(0, $data);
    }

    public function checkPassage($bankCode, $repaymentMoney, $selectDays, $userLevel, $passageId)
    {
        $userLevelPassage =  $this->userLevelPassageRepository->first($passageId, $userLevel);
        $amount = $this->isCanRecommend($passageId, $bankCode, $repaymentMoney, $userLevelPassage->rate, $userLevelPassage->second_rate, false);
        if (empty($amount)) {
            return $this->responseJson(10901);//暂不支持该银行
        }
        //剩余天数 >= 小额最小天数 使用小额 3笔
        if ($selectDays >= $amount['minDays']) {
            $times = 3;
            $recommendDays = $amount['minDays'];
            //推荐天数、还款金额、还款手续费、最低卡余额、通道id
            $repaymentPlanServiceCharge = $this->repaymentPlanServiceCharge($repaymentMoney, $userLevelPassage->rate,
                $selectDays, $times, $userLevelPassage->second_rate);
            $data = [
                'repayment_money' => round($repaymentMoney),
                'repayment_service_charge' => $repaymentPlanServiceCharge,
                'lowest_card_money' => $this->lowestCardMoney($repaymentMoney, $selectDays,
                    $times, $repaymentPlanServiceCharge),
                'passage_id' => $passageId,
                'recommend_days' => $recommendDays,
                'highest_money' => $amount['highestOneDayOneTimesRepaymentMoney'],
                'personal_rate' => $userLevelPassage->rate,//会员使用费率
                'second_rate' => $userLevelPassage->second_rate,//秒到费
                'times' => $times
            ];
            return $data;
        }
        //剩余天数 >= 小额最小天数 使用小额 5笔
        if ($selectDays >= $amount['maxDays']) {
            $times = 5;
            $recommendDays = $amount['maxDays'];
            //推荐天数、还款金额、还款手续费、最低卡余额、通道id
            $repaymentPlanServiceCharge = $this->repaymentPlanServiceCharge($repaymentMoney, $userLevelPassage->rate,
                $selectDays, $times, $userLevelPassage->second_rate);
            $data = [
                'repayment_money' => round($repaymentMoney),
                'repayment_service_charge' => $repaymentPlanServiceCharge,
                'lowest_card_money' => $this->lowestCardMoney($repaymentMoney, $selectDays,
                    $times, $repaymentPlanServiceCharge),
                'passage_id' => $passageId,
                'recommend_days' => $recommendDays,
                'highest_money' => $amount['highestOneDayOneTimesRepaymentMoney'],
                'personal_rate' => $userLevelPassage->rate,//会员使用费率
                'second_rate' => $userLevelPassage->second_rate,//秒到费
                'times' => $times
            ];
            return $data;
        }
        return $this->responseJson(10519);//所选还款天数不足
    }

    /**
     * 获取所支持的通道
     * @param $bankCode
     * @param $repaymentMoney
     * @param $remainingDays
     * @param $userLevel
     */
    public function getSupportPassage($bankCode, $repaymentMoney, $remainingDays, $userLevel)
    {
        $userLevelPassageSmall =  $this->userLevelPassageRepository->first(1, $userLevel);
        $smallAmount = $this->isCanRecommend(1, $bankCode, $repaymentMoney, $userLevelPassageSmall->rate, $userLevelPassageSmall->second_rate);
        if (empty($smallAmount)) return [];
        //剩余天数 >= 小额最小天数 使用小额 3笔
        if ($remainingDays >= $smallAmount['minDays'] && $smallAmount['passage_id'] == 1) {
            return [
                'repayment_money' => $repaymentMoney,
                'passage_id' => 1,
                'recommend_days' => $smallAmount['minDays'],
                'highestOneDayOneTimesRepaymentMoney' => $smallAmount['highestOneDayOneTimesRepaymentMoney'],
                'personal_rate' => $userLevelPassageSmall->rate,//会员使用费率
                'second_rate' => $userLevelPassageSmall->second_rate,//秒到费
                'times' => 3,
            ];
        }
        //剩余天数 >= 小额最小天数 使用小额 5笔
        if ($remainingDays >= $smallAmount['maxDays'] && $smallAmount['passage_id'] == 1) {
            return [
                'repayment_money' => $repaymentMoney,
                'passage_id' => 1,
                'recommend_days' => $smallAmount['maxDays'],
                'highestOneDayOneTimesRepaymentMoney' => $smallAmount['highestOneDayOneTimesRepaymentMoney'],
                'personal_rate' => $userLevelPassageSmall->rate,//会员使用费率
                'second_rate' => $userLevelPassageSmall->second_rate,//秒到费
                'times' => 5,
            ];
        }
        $userLevelPassageLarge =  $this->userLevelPassageRepository->first(3, $userLevel);
        $largeAmount = $this->isCanRecommend(3, $bankCode, $repaymentMoney, $userLevelPassageLarge->rate, $userLevelPassageLarge->second_rate);
        if (empty($largeAmount)) return [];
        //剩余天数 >= 小额最小天数 使用大额 3笔
        if ($remainingDays >= $largeAmount['minDays'] && $largeAmount['passage_id'] == 3) {
            return [
                'repayment_money' => $repaymentMoney,
                'passage_id' => 3,
                'recommend_days' => $largeAmount['minDays'],
                'highestOneDayOneTimesRepaymentMoney' => $largeAmount['highestOneDayOneTimesRepaymentMoney'],
                'personal_rate' => $userLevelPassageLarge->rate,//会员使用费率
                'second_rate' => $userLevelPassageLarge->second_rate,//秒到费
                'times' => 3,
            ];
        }
        return [
            'repayment_money' => $repaymentMoney,
            'passage_id' => 1,
            'recommend_days' => 0,
            'highestOneDayOneTimesRepaymentMoney' => 0,
            'personal_rate' => $userLevelPassageSmall->rate,//会员使用费率
            'second_rate' => $userLevelPassageSmall->second_rate,//秒到费
            'times' => 0,
        ];
    }

    /**
     * 最低卡余额
     * @param $repaymentMoney
     * @param $days
     * @param $times
     * @param $serviceCharge
     * @return float
     */
    public function lowestCardMoney($repaymentMoney, $days, $times, $serviceCharge)
    {
        $avg = round($repaymentMoney / ($days * $times));
        $res = ceil(($avg + $serviceCharge) * $times);
        return $res;
    }

    /**
     * 生成还款账单
     * 消费时间，在早上9点15分到下午7点30分之间，
     * 第一笔消费在9点15分到10点30分之间，
     * 之后每笔消费间距时间在110到140分钟之间，
     * 每天还款时间是最后一笔消费交易完成后的30到60分钟之内
     * 3笔消费 90-130
     * 第一笔 09:30-10:45
     * 最后一笔 19:25
     * 5笔消费 120-180
     * 第一笔 10:00-12:30
     * 最后一笔 18:30
     * @param $userId
     * @param $personalRate
     * @param $creditId
     * @param $address
     * @param $repaymentMoneys
     * @param $repaymentDates
     * @param $secondRate
     * @return \Illuminate\Http\JsonResponse|mixed
     */
    public function makeRepaymentBill($userId, $userLevel, $creditId, $address, $repaymentMoneys, $repaymentDates, $passageId)
    {
        //判断是否有绑定
        $isBind = $this->userCreditCardRepository->validateCreditCardIsUser($creditId, $userId);
        if (empty($isBind->bank_no) || 0 == $isBind->is_bind) {
            return $this->responseJson(10306);//信用卡不存在
        }
        //一个月有上个和这个还款日，两个的处理
        $monthBillDate = getMonthBillDate($isBind->bill_day, $isBind->repayment_day);
        $bill = $this->repaymentBillRepository->getRepaymentBill($userId, $creditId, $monthBillDate);
        if (empty($bill)) {
            return $this->responseJson(10400);//账单不存在
        }
        $repaymentMoneyAll = roundNo($repaymentMoneys);//不四舍五入保留两位
        $repaymentMoney = intval($repaymentMoneys);//保留整数
        $bill->update([
            'repayment_bill_money' => $repaymentMoneyAll,
            'lowest_repayment_money' => ceilDecimal($repaymentMoneyAll * 0.1, 2),//本期最低应还金额
            'consume_address' => $address,
            'update_time' => time(),
        ]);
        $dates = json_decode($repaymentDates, true);
        if (!is_array($dates)) {
            return $this->responseJson(422, [], false, '还款日期格式不正确', '还款日期格式不正确');
        }
        $dates = array_values(array_unique($dates));
        $dates = $this->repaymentDateIsOk($dates, $bill->bill_date, $bill->repayment_date);//用户选择的还款日期
        if (is_object($dates)) return $dates;
        $selectDays = count($dates);//总天数
        if ($selectDays < 2) {
            return $this->responseJson(10520);//至少选择2天以上
        }
        $isCanFinishPlan = $this->checkPassage($isBind->bank_code, $repaymentMoneys, $selectDays, $userLevel, $passageId);
        if (is_object($isCanFinishPlan)) return $isCanFinishPlan;
        $userLevelPassage =  $this->userLevelPassageRepository->first($passageId, $userLevel);
        $result = $this->makePlan($passageId, $isCanFinishPlan['highest_money'], $dates, $repaymentMoneyAll,
            $repaymentMoney, $userLevelPassage->rate, $selectDays, $isCanFinishPlan['times'], $userLevelPassage->second_rate);
        return $this->responseJson(0, $result);
    }

    /**
     * 时间戳转日期
     * @param $timestamps
     * @return array
     */
    protected function timestampToDate($timestamps)
    {
        $data = [];
        foreach ($timestamps as $key=>$value) {
            $data[$key] = date('Y-m-d', $value);
        }
        return $data;
    }

    /**
     * 还款日期是否满足条件
     * @param $dates
     * @param $billDate
     * @param $repaymentDate
     * @return \Illuminate\Http\JsonResponse
     */
    public function repaymentDateIsOk($dates, $billDate, $repaymentDate)
    {
        if (!empty($dates)) {
            $limitEndTime = strtotime('10:00');
            foreach ($dates as $key=>$value) {
                if (!strtotime($value)) {
                    return $this->responseJson(422, [], false, '还款日期格式不正确', '还款日期格式不正确');
                }
                //是否<账单日
                if ($value < date('Y-m-d', $billDate)) {
                    return $this->responseJson(10500);//还没到账单日
                }
                //小于今天0点的都不可以选择
                if ($value < date('Y-m-d')) {
                    return $this->responseJson(10501);//今天之前的日期不能选择
                }
                //等于今天的 > 10:00不给选择
                if (date('Y-m-d') == $value) {
                    if (time() > $limitEndTime) {
                        return $this->responseJson(10502);//今天的日期不能大于今天10:00
                    }
                }
                //是否>=还款日
                if ($value >= date('Y-m-d', $repaymentDate)) {
                    return $this->responseJson(10503);//不能大于等于还款日期
                }
            }
            return $dates;
        } else {
            return $this->responseJson(422, [], false, '还款日期格式不正确', '还款日期格式不正确');
        }
    }

    /**
     * 制作计划
     * @param $dates
     * @param $repaymentMoneyAll
     * @param $repaymentMoney
     * @param $personalRate
     * @param $days
     * @param $times
     * @param $secondRate
     * @return array
     */
    public function makePlan($passageId, $highestMoney, $dates, $repaymentMoneyAll, $repaymentMoney, $personalRate, $days, $times, $secondRate)
    {
        $decimal = round($repaymentMoneyAll - $repaymentMoney, 2);//拿出小数点
        $repaymentPlanServiceCharge = $this->repaymentPlanServiceCharge($repaymentMoneyAll, $personalRate, $days, $times, $secondRate);
        $repaymentMoneyEveryTime = $this->randNumber($repaymentMoney, $days, $highestMoney * $times);
        $data = [];
        foreach ($repaymentMoneyEveryTime as $kk=>$val) {
            $data[$kk]['repayment_every_time_date'] = $dates[$kk];
            $repaymentMoneyEveryDay = $this->randNumber($val, $times, $highestMoney, 2);
            $detail = $this->repaymentEveryTimeDetail($passageId, $kk, $repaymentMoneyEveryDay, $decimal,
                $repaymentPlanServiceCharge, $times, $highestMoney, $personalRate, $secondRate, $val);
            $endConsumeTime = end($detail);
            $data[$kk]['repayment_every_time'] = $this->randTimeNext($endConsumeTime['consume_time'], 1000);
            $data[$kk]['repayment_every_time_money'] = (0 == $kk) ? $val + $decimal : $val;
            $data[$kk]['repayment_passage_id'] = $passageId;
            $data[$kk]['detail'] = $detail;
        }
        //最后一天，还款时间作为完成计划时间
        $end = end($data);
        $finishPlanTime = strtotime($end['repayment_every_time_date'] . '' . $end['repayment_every_time']);
        $result = [
            'create_bill_time' => date('Y-m-d'),
            'finish_plan_time' => $finishPlanTime,
            'repayment_money' => $repaymentMoneyAll,
            'repayment_days' => $days,
            'service_charge' => $this->repaymentPlanServiceCharge,
            'lowest_card_money' => $this->lowestCardMoney,
            'passage_id' => $passageId,
            'bill' => $this->dealDecimalDiff($data, $repaymentMoneyAll),
        ];
        return $result;
    }

    /**
     * 处理小数差值，将差值算到第一笔
     */
    public function dealDecimalDiff($data, $repaymentMoneyAll)
    {
        $consumeMoney = [];
        $consumeServiceCharge = [];
        foreach ($data as $value) {
            foreach ($value['detail'] as $k=>$val) {
                $consumeMoney[] = $val['consume_money'];
                $consumeServiceCharge[] = $val['consume_service_charge'];
            }
        }
        $diffNumConsumeMoney = round($repaymentMoneyAll + $this->repaymentPlanServiceCharge - array_sum($consumeMoney), 2);
        $diffNumConsumeServiceCharge = round($this->repaymentPlanServiceCharge - array_sum($consumeServiceCharge), 2);
        //不管谁大谁小都需要加或减，否则手续费不对应，计划会失败
        foreach ($data as $key=>$value) {
            foreach ($value['detail'] as $k=>$val) {
                if (0 == $key && 0 == $k) {
                    if ($val['consume_passage_id'] == 1) {
                        $data[0]['detail'][0]['consume_money'] = round($val['consume_money'] + $diffNumConsumeMoney, 2);
                        $data[0]['detail'][0]['consume_service_charge'] = round($val['consume_service_charge'] + $diffNumConsumeServiceCharge, 2);
                    }
                    if ($val['consume_passage_id'] == 3) {
                        $consumeEveryTimePrice = round($val['consume_every_time_price'] + $diffNumConsumeMoney + $diffNumConsumeServiceCharge, 2);
                        $data[0]['detail'][0]['consume_service_charge'] = $this->consumeServiceCharge($val['consume_money'], $val['consume_rate'], $consumeEveryTimePrice);
                        $data[0]['detail'][0]['consume_every_time_price'] = sprintf("%.4f", $consumeEveryTimePrice);
                    }
                }
            }
        }
        return $data;
    }

    /**
     * 每日消费与每一笔消费详情
     * @param $kk
     * @param $repaymentMoneyEveryDay
     * @param $decimal
     * @param $repaymentPlanServiceCharge
     * @param $times 多少笔
     * @param $oneDayRepaymentMoney 第一天的还款金额 + 手续费算卡余额
     * @return array
     */
    public function repaymentEveryTimeDetail($passageId, $kk, $repaymentMoneyEveryDay, $decimal, $repaymentPlanServiceCharge,
                                             $times, $highestMoney, $personalRate, $secondRate, $oneDayRepaymentMoney)
    {
        if ($times <= 3) {
            $begintime = '10:00';
            $endtime = '12:30';
        }
        if ($times > 3 && $times <= 5) {
            $begintime = '09:30';
            $endtime = '10:45';
        }
        $data = [];
        foreach ($repaymentMoneyEveryDay as $key=>$item) {
            $shopType = $this->randShopType($passageId, $key + 1);
            if (0 == $key) {
                $firstRandTime = $this->randTime($begintime, $endtime);
                $data[$key]['consume_money'] = $item;
                $data[$key]['consume_time'] = $firstRandTime;
                $data[$key]['consume_service_charge'] = $this->consumeServiceCharge($item, $personalRate, $secondRate);
                $data[$key]['consume_rate'] = $personalRate;
                $data[$key]['consume_every_time_price'] = $secondRate;
                $data[$key]['consume_passage_id'] = $passageId;
            } else {
                $randTime = $this->randTimeNext($data[$key - 1]['consume_time'], $times);
                $data[$key]['consume_money'] = $item;
                $data[$key]['consume_time'] = $randTime;
                $data[$key]['consume_service_charge'] = $this->consumeServiceCharge($item, $personalRate, $secondRate);
                $data[$key]['consume_rate'] = $personalRate;
                $data[$key]['consume_every_time_price'] = $secondRate;
                $data[$key]['consume_passage_id'] = $passageId;
            }
            $data[$key]['consume_type_mcc'] = $shopType->mcc;
            $data[$key]['consume_type_name'] = $shopType->display_name;
        }
        if (0 == $kk) {
            return $this->isOverMaxConsumeMoney($passageId, $data, $repaymentPlanServiceCharge, $decimal, $highestMoney,
                $personalRate, $secondRate, $oneDayRepaymentMoney);
        } else {
            return $data;
        }
    }

    /**
     * 是否超过最大消费金额
     * @param $data
     * @param $repaymentPlanServiceCharge
     * @param $decimal
     * @param $highestMoney
     * @param $personalRate
     * @param $secondRate
     * @return array
     */
    public function isOverMaxConsumeMoney($passageId, $data, $repaymentPlanServiceCharge, $decimal, $highestMoney, $personalRate, $secondRate, $oneDayRepaymentMoney)
    {
        //第一笔消费总金额 消费金额 + 还款小数部分 + 还款计划手续费
        $oneTimesCountMoney = round($data[0]['consume_money'] + $decimal + $repaymentPlanServiceCharge, 2);
        //是否大于最高单笔还款金额则单独作一笔消费金额，多出的需要多算一笔手续费
        if ($oneTimesCountMoney >= $highestMoney) {
            $oneConsumeMoney = round($oneTimesCountMoney - $data[0]['consume_money'], 2);
            //单笔手续费
            $serviceCharge = $this->overOnetTimesRepaymentPlanServiceCharge($personalRate, 1);
            $result[0]['consume_money'] = round($oneConsumeMoney + $serviceCharge, 2);
            $res = array_merge($result, $data);
            $times = count($res);
            if ($times <= 3) {
                $begintime = '10:00';
                $endtime = '12:30';
            }
            if ($times > 3 && $times <= 6) {
                $begintime = '09:30';
                $endtime = '10:45';
            }
            $newResult = [];
            foreach ($res as $key=>$item) {
                $shopType = $this->randShopType($passageId, $key + 1);
                if (0 == $key) {
                    $firstRandTime = $this->randTime($begintime, $endtime);
                    $newResult[$key]['consume_money'] = $oneConsumeMoney + $serviceCharge;
                    $newResult[$key]['consume_time'] = $firstRandTime;
                    $newResult[$key]['consume_service_charge'] = $serviceCharge;
                    $newResult[$key]['consume_rate'] = $personalRate;
                    $newResult[$key]['consume_every_time_price'] = $secondRate;
                    $newResult[$key]['consume_passage_id'] = $passageId;
                } else {
                    $randTime = $this->randTimeNext($newResult[$key - 1]['consume_time'], $times);
                    $newResult[$key]['consume_money'] = $item['consume_money'];
                    $newResult[$key]['consume_time'] = $randTime;
                    $newResult[$key]['consume_service_charge'] = $this->consumeServiceCharge($item['consume_money'], $personalRate, $secondRate);
                    $newResult[$key]['consume_rate'] = $personalRate;
                    $newResult[$key]['consume_every_time_price'] = $secondRate;
                    $newResult[$key]['consume_passage_id'] = $passageId;
                }
                $newResult[$key]['consume_type_mcc'] = $shopType->mcc;
                $newResult[$key]['consume_type_name'] = $shopType->display_name;
            }
            $this->repaymentPlanServiceCharge = ceilDecimal($repaymentPlanServiceCharge + $serviceCharge, 2);
            $this->lowestCardMoney = ceil($oneDayRepaymentMoney + $repaymentPlanServiceCharge + $serviceCharge);
        } else {
            $times = count($data);
            if ($times <= 3) {
                $begintime = '10:00';
                $endtime = '12:30';
            }
            if ($times > 3 && $times <= 6) {
                $begintime = '09:30';
                $endtime = '10:45';
            }
            $newResult = [];
            foreach ($data as $key=>$item) {
                $shopType = $this->randShopType($passageId, $key + 1);
                if (0 == $key) {
                    $firstRandTime = $this->randTime($begintime, $endtime);
                    $newResult[$key]['consume_money'] = $oneTimesCountMoney;
                    $newResult[$key]['consume_time'] = $firstRandTime;
                    $newResult[$key]['consume_service_charge'] = $this->consumeServiceCharge($oneTimesCountMoney, $personalRate, $secondRate);
                    $newResult[$key]['consume_rate'] = $personalRate;
                    $newResult[$key]['consume_every_time_price'] = $secondRate;
                    $newResult[$key]['consume_passage_id'] = $passageId;
                } else {
                    $randTime = $this->randTimeNext($newResult[$key - 1]['consume_time'], $times);
                    $newResult[$key]['consume_money'] = $item['consume_money'];
                    $newResult[$key]['consume_time'] = $randTime;
                    $newResult[$key]['consume_service_charge'] = $this->consumeServiceCharge($item['consume_money'], $personalRate, $secondRate);
                    $newResult[$key]['consume_rate'] = $personalRate;
                    $newResult[$key]['consume_every_time_price'] = $secondRate;
                    $newResult[$key]['consume_passage_id'] = $passageId;
                }
                $newResult[$key]['consume_type_mcc'] = $shopType->mcc;
                $newResult[$key]['consume_type_name'] = $shopType->display_name;
            }
            $this->repaymentPlanServiceCharge = $repaymentPlanServiceCharge;
            $this->lowestCardMoney = ceil($oneDayRepaymentMoney + $repaymentPlanServiceCharge);
        }
        return $newResult;
    }

    /**
     * 随机产生时分
     * @param $startTime
     * @param $endTime
     * @return false|string
     */
    public function randTime($startTime, $endTime)
    {
        return date('H:i', strtotime(randomDate($startTime, $endTime)));
    }

    /**
     * 随机产生时分之间的随机间隔时间
     * @param $startTime
     * @return false|string
     */
    public function randTimeNext($startTime, $times)
    {
        if ($times <= 3) {
            $diffTime = rand(120, 180);
        }
        if ($times > 3 && $times <= 5) {
            $diffTime = rand(90, 130);
        }
        if ($times == 6) {
            $diffTime = rand(90, 100);
        }
        if ($times == 1000) {
            $diffTime = rand(30, 60);
        }
        return date('H:i', strtotime($startTime) + $diffTime * 60);
    }

    /**
     * 获取消费类型
     * @return mixed
     */
    public function getShopType()
    {
        $url = 'http://pay.huanqiuhuiju.com/authsys/api/merchsPool/getMerchsPool.do';
        $client = new \GuzzleHttp\Client();
        $response = $client->request('get', $url);
        $json = json_decode($response->getBody()->getContents(), true);
        return $json;
    }

    /**
     * 随机获取消费类型
     * @return mixed
     */
    public function randShopType($passageId, $consumeEveryTime)
    {
        if ($passageId == 3) {
            $data = [
                'mcc' => '',
                'display_name' => '',
            ];
            return (object)$data;
        }
        if ($consumeEveryTime > 3) {
            $consumeEveryTime = 1;
        }
        $shopTypesRules = DB::table('consume_type_rules')->where('consume_every_time', $consumeEveryTime)->get()->toArray();
        $shopTypesRulesIds = array_column($shopTypesRules, 'consume_type_id');
        $shopTypes = DB::table('consume_type')->whereIn('id',  $shopTypesRulesIds)->get()->toArray();
        shuffle($shopTypes);
        $key = mt_rand(0, count($shopTypes) - 1);
        return $shopTypes[$key];
    }

    /**
     * 最高一天一次还款金额
     * 最小天数 至少2天
     * 最大天数
     * @param $repaymentMoney
     * @param $personalRate
     * @param $secondRate
     * @return array
     */
    public function highestOneDayOneTimesRepaymentMoney($passageId, $repaymentMoney, $personalRate, $secondRate, $repaymentEveryTimeMoney)
    {
        $oneTimesServiceCharge = $this->repaymentPlanServiceCharge($repaymentEveryTimeMoney, $personalRate, 1, 1, $secondRate);
        //1天1笔最高还款金额
        $highestOneDayOneTimesRepaymentMoney = $repaymentEveryTimeMoney - $oneTimesServiceCharge;
        $minDays = ceil(($repaymentMoney) / (3 * $highestOneDayOneTimesRepaymentMoney));
        $minDays = intval($minDays);
        $maxDays = ceil(($repaymentMoney) / (5 * $highestOneDayOneTimesRepaymentMoney));
        $maxDays = intval($maxDays);
        $result = [
            'highestOneDayOneTimesRepaymentMoney' => $highestOneDayOneTimesRepaymentMoney,
            'minDays' => $minDays == 1 ? $minDays + 1 : $minDays,
            'maxDays' => $maxDays == 1 ? $maxDays + 1 : $maxDays,
            'passage_id' => $passageId,
        ];
        return $result;
    }

    /**
     * 剩余还款天数
     * @param $billDate
     * @param $repaymentDay
     * @return int
     */
    public function remainingRepaymentDays($repaymentDay)
    {
        if (time() > strtotime('09:30')) {
            $startDay = date('d') + 1;
        } else {
            $startDay = date('d');
        }
        $billRepaymentDate = billRepaymentDate($startDay, $repaymentDay);
        $endDateTimestamp = strtotime($billRepaymentDate['bill_date']) + 86400 * $billRepaymentDate['diff_days'];
        $dates = getDateFromRange($billRepaymentDate['bill_date'], date('Y-m-d', $endDateTimestamp));
        return [
            'remaining_days' => $billRepaymentDate['diff_days'],
            'dates' => $dates,
        ];
    }

    /**
     * 第一次消费金额
     * @param $repaymentMoneyEveryTime 第一次消费金额
     * @param $repaymentPlanServiceCharge 还款计划手续费
     * @return mixed
     */
    public function firstTimesConsumeMoney($repaymentMoneyEveryTime, $repaymentPlanServiceCharge)
    {
        return $repaymentMoneyEveryTime + $repaymentPlanServiceCharge;
    }

    /**
     * 消费金额到还款金账户
     * @param $consumeMoney 消费金额
     * @param $personalRate 个人费率
     * @param $secondRate 秒到费
     * @return float
     */
    public function consumeMoneyToRepaymentAccount($consumeMoney, $personalRate, $secondRate)
    {
        return round(($consumeMoney - $consumeMoney * $personalRate - $secondRate), 2);
    }

    /**
     * 总和随机数算法
     * @param $repaymentMoney
     * @param $days
     * @param bool $baseNumber 0还款 1还款或消费极端值 2消费
     * @return array
     */
    public function randNumber($repaymentMoney, $days, $limit = false, $baseNumber = 0)
    {
        $avg = round($repaymentMoney / $days);
        $base = 1;
        if (1 == $baseNumber) {
            $base = floor($avg * 0.01);
        }
        if (0 == $baseNumber) {
            $base = floor($avg * 0.07);
        }
        $min = $avg - $base;
        if (0 >= $min) {
            $min = 1;
            $max = 1;
        } else {
            $max = $avg + $base;
        }
        if (2 == $baseNumber) {
            $min = $avg;
            $max = $limit;
        }
        $array = [];
        for ($i = 0; $i < $days - 1; $i ++) {
            $array[$i] =  mt_rand($min, $max);
            if ($array[$i] > $limit) {
                return $this->randNumber($repaymentMoney, $days, $limit, $baseNumber);
            }
        }
        $this->endFor ++;
        //死循环处理
        if (50000 < $this->endFor) {
            die('{"code":401,"msg":"机器不行了，你自己算吧！0.0","message":""}');
        }
        $lastNumber = $repaymentMoney - array_sum($array);
        if (0 >= $lastNumber) {
            return $this->randNumber($repaymentMoney, $days, $limit, $baseNumber);
        }
        if ($max < $lastNumber) {
            return $this->randNumber($repaymentMoney, $days, $limit, 1);
        }
        if ($lastNumber > $limit) {
            return $this->randNumber($repaymentMoney, $days, $limit, $baseNumber);
        }
        if ($lastNumber < 20) {
            return $this->randNumber($repaymentMoney, $days, $limit, $baseNumber);
        }
        $array = array_merge($array, [$lastNumber]);
        if ($baseNumber < 2) {
            rsort($array);
        }
        if (empty($array)) {
            return $this->randNumber($repaymentMoney, $days, $limit, $baseNumber);
        }
        return $array;
    }
}
